package com.campus.runrun.common.shiro;


import com.campus.runrun.common.exception.CustomException;
import com.campus.runrun.common.exception.ResultCodeEnum;
import com.campus.runrun.common.utils.SpringContextUtils;
import com.campus.runrun.model.vo.UserVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authz.UnauthorizedException;
import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter;
import org.apache.shiro.web.util.WebUtils;
import org.springframework.data.redis.core.RedisTemplate;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.concurrent.TimeUnit;

/**
 * @author BichonCode
 * @mail chenzhichaohh@163.com
 * @create 2020/08/05
 */
@Slf4j
public class JWTFilter extends BasicHttpAuthenticationFilter {

    private static final ThreadLocal<UserVO> USER_INFO = new ThreadLocal<>();

    @Override
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws UnauthorizedException {
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        String token = httpServletRequest.getHeader("Authorization");
        if (token == null) {
            throw new CustomException(ResultCodeEnum.MISSING_TOKEN_ERROR);
        }
        boolean b = JWTUtil.verifyToken(token);


        if (!b) {
            return false;
            //throw new IllegalStateException("非法令牌，无权访问");
        }
        RedisTemplate redisTemplate = (RedisTemplate) SpringContextUtils.getBean("redisTemplate");

        // 根据token解密，解密出jwt-id，先从redis中查出redisToken，判断是否相同
        String redisToken = (String) redisTemplate.opsForValue().get(JWTUtil.getJwtIdByToken(token));
        if (!token.equals(redisToken)) {
           return false;
        }


        // 将用户信息设置进本地线程域
        UserVO userInfo = JWTUtil.getUserInfoByToken(token);
        USER_INFO.set(userInfo);
        JwtToken jwtToken = new JwtToken(token, "MyRealm");
        // 提交给realm进行登入，如果错误他会抛出异常并被捕获,无错误的化灰继续延长token的有效期
        getSubject(request, response).login(jwtToken);

        // 如果没有抛出异常则代表登入成功，返回true
        return true;

    }

    public static UserVO getUserInfo() {
        UserVO userInfo = USER_INFO.get();
        USER_INFO.remove();
        return userInfo;
    }

    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
        HttpServletResponse httpServletResponse = (HttpServletResponse) response;
        // 这里是个坑，如果不设置的接受的访问源，那么前端都会报跨域错误，因为这里还没到corsConfig里面
        httpServletResponse.setHeader("Access-Control-Allow-Origin", ((HttpServletRequest) request).getHeader("Origin"));
        httpServletResponse.setHeader("Access-Control-Allow-Credentials", "true");
        httpServletResponse.setCharacterEncoding("UTF-8");
        httpServletResponse.setContentType("application/json");
        WebUtils.toHttp(response).sendError(HttpServletResponse.SC_UNAUTHORIZED, "权限认证失败，访问被拒绝");
        return false;
    }

}
